﻿package de.gameduell.framework.facebook.communication {
	import de.gameduell.framework.facebook.reporting.FBBaseTracker;
	import de.gameduell.facebook.service.gen.FireEventResponse;
	import de.gameduell.facebook.service.gen.FireEvent;
	import de.gameduell.facebook.service.gen.FireEventRequest;
	import de.gameduell.facebook.service.gen.GetJackpotTimeLeftInSecondsResponse;
	import de.gameduell.facebook.service.gen.GetJackpotTimeLeftInSeconds;
	import de.gameduell.facebook.service.gen.GetJackpotTimeLeftInSecondsRequest;
	import de.gameduell.facebook.service.gen.FetchJackPotResponse;
	import de.gameduell.facebook.service.gen.FetchJackPot;
	import de.gameduell.facebook.service.gen.FetchJackPotRequest;
	import de.gameduell.facebook.service.gen.GetCurrentJackPot;
	import de.gameduell.facebook.service.gen.GetCurrentJackPotResponse;
	import de.gameduell.facebook.service.gen.GetCurrentJackPotRequest;
	import de.gameduell.facebook.service.gen.UpdateJackPotScoreResponse;
	import de.gameduell.facebook.service.gen.UpdateJackPotScore;
	import de.gameduell.facebook.service.gen.UpdateJackPotScoreRequest;
	import de.gameduell.facebook.service.gen.StartJackPotGameResponse;
	import de.gameduell.facebook.service.gen.StartJackPotGame;
	import de.gameduell.facebook.service.gen.StartJackPotGameRequest;
	import de.gameduell.facebook.service.gen.UpdateScore;
	import de.gameduell.facebook.service.gen.UpdateScoreResponse;
	import de.gameduell.facebook.service.gen.UpdateScoreRequest;
	import de.gameduell.framework.facebook.event.DonationURLEvent;
	import de.gameduell.framework.facebook.event.CommunicationErrorEvent;
	import de.gameduell.facebook.service.gen.CatalogItem;
	import de.gameduell.facebook.service.gen.DeleteGamestate;
	import de.gameduell.facebook.service.gen.DeleteGamestateRequest;
	import de.gameduell.facebook.service.gen.DeleteGamestateResponse;
	import de.gameduell.facebook.service.gen.FetchGamestate;
	import de.gameduell.facebook.service.gen.FetchGamestateRequest;
	import de.gameduell.facebook.service.gen.FetchGamestateResponse;
	import de.gameduell.facebook.service.gen.FetchGamestates;
	import de.gameduell.facebook.service.gen.FetchGamestatesRequest;
	import de.gameduell.facebook.service.gen.FetchGamestatesResponse;
	import de.gameduell.facebook.service.gen.GameState;
	import de.gameduell.facebook.service.gen.GenerateDonationURL;
	import de.gameduell.facebook.service.gen.GenerateDonationURLRequest;
	import de.gameduell.facebook.service.gen.GenerateDonationURLResponse;
	import de.gameduell.facebook.service.gen.GetCatalogItems;
	import de.gameduell.facebook.service.gen.GetCatalogItemsRequest;
	import de.gameduell.facebook.service.gen.GetCatalogItemsResponse;
	import de.gameduell.facebook.service.gen.GetCurrentTimestamp;
	import de.gameduell.facebook.service.gen.GetCurrentTimestampRequest;
	import de.gameduell.facebook.service.gen.GetCurrentTimestampResponse;
	import de.gameduell.facebook.service.gen.GetFriendsResponse;
	import de.gameduell.facebook.service.gen.GetFriendsWithGameInstalled;
	import de.gameduell.facebook.service.gen.GetFriendsWithGameInstalledRequest;
	import de.gameduell.facebook.service.gen.GetUserBalance;
	import de.gameduell.facebook.service.gen.GetUserBalanceRequest;
	import de.gameduell.facebook.service.gen.GetUserBalanceResponse;
	import de.gameduell.facebook.service.gen.GetUserProfile;
	import de.gameduell.facebook.service.gen.GetUserProfileRequest;
	import de.gameduell.facebook.service.gen.GetUserProfileResponse;
	import de.gameduell.facebook.service.gen.GetUsersProfiles;
	import de.gameduell.facebook.service.gen.GetUsersProfilesRequest;
	import de.gameduell.facebook.service.gen.GetUsersProfilesResponse;
	import de.gameduell.facebook.service.gen.InitializeClient;
	import de.gameduell.facebook.service.gen.InitializeClientRequest;
	import de.gameduell.facebook.service.gen.InitializeClientResponse;
	import de.gameduell.facebook.service.gen.Purchase;
	import de.gameduell.facebook.service.gen.PurchaseRequest;
	import de.gameduell.facebook.service.gen.PurchaseResponse;
	import de.gameduell.facebook.service.gen.StartGame;
	import de.gameduell.facebook.service.gen.StartGameRequest;
	import de.gameduell.facebook.service.gen.StartGameResponse;
	import de.gameduell.facebook.service.gen.StoreGamestate;
	import de.gameduell.facebook.service.gen.StoreGamestateRequest;
	import de.gameduell.facebook.service.gen.StoreGamestateResponse;
	import de.gameduell.framework.debug.Debug;
	import de.gameduell.framework.facebook.FBBaseGameState;
	import de.gameduell.framework.facebook.IFBBaseController;
	import de.gameduell.framework.facebook.event.GameStateEvent;

	import com.google.protobuf.Message;

	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;

	public class ServiceLayerCommunication extends EventDispatcher {
		public static const SESSION_EXPIRED:int = 2;
		public static const MESSAGE_OK:int = 0;
		public static const MESSAGE_ERROR:int = 1;
		
		public static const UNKNOWN_RETURN_CODE_ERROR:String = "UNKNOWN_RETURN_CODE_ERROR";
		public static const COMMUNICATION_ERROR:String = "COMMUNICATION_ERROR";
		public static const SESSION_EXPIRED_ERROR:String = "SESSION_EXPIRED";
		public static const INVALID_RESPONSE_ERROR:String = "INVALID_RESPONSE_ERROR";
		public static const GENERAL_NETWORK_ERROR:String = "GENERAL_NETWORK_ERROR";
		public static const SERVER_NOT_AVAILABLE_ERROR:String = "SERVER_NOT_AVAILABLE_ERROR";
		public static const MESSAGE_ERROR_1:String = "1";
		public static const PURCHASE_ITEM_FAILED:String = "PURCHASE_ITEM_FAILED";
		public static const DONATION_URL_RESPONSE:String = "DONATION_URL_RESPONSE";
		public static const FOREIGN_GAMESTATE_RECEIVED:String = "FOREIGN_GAMESTATE_RECEIVED";

		private var serviceURL:String;
		private var sessionId:String;
		private var facebookData:FacebookData;
		private var controller:IFBBaseController;
		private var gameState:FBBaseGameState;
		private var tracker:FBBaseTracker;

		public function ServiceLayerCommunication(aController:IFBBaseController){
			tracker = FBBaseTracker.getInstance();
			controller   = aController;
			gameState    = controller.gameState;
			facebookData = controller.facebookData;
			serviceURL   = facebookData.serverPrefix;
			sessionId    = facebookData.sessionId;
			
			ServiceLayerRequestAction.safeRequests = new Array((new DeleteGamestate()).endpoint, (new StoreGamestate()).endpoint,(new Purchase()).endpoint);
		}

		// ################################## request methods ##########################################

		public function requestFireEvent(eventType:String, jsonParams:String):void {
			Debug.trace("ServiceLayerCommunication::requestFireEvent: eventType: " + eventType + " jsonParams:" +  jsonParams, Debug.DEBUG);
			var request:FireEventRequest = new FireEventRequest();
			request.eventType = eventType;
			request.jsonParams = jsonParams;
			sendRequest(request, receiveFireEventResponse, (new FireEvent()).endpoint, false);
		}

		public function requestGetJackpotTimeLeftInSeconds(event:Event = null):void {
			var request:GetJackpotTimeLeftInSecondsRequest = new GetJackpotTimeLeftInSecondsRequest();
			Debug.trace("ServiceLayerCommunication::requestGetJackpotTimeLeftInSeconds: currentJackpotId: " + controller.applicationData.jackpot.currentJackpotId, Debug.FACEBOOK);
			request.gameid = controller.applicationData.jackpot.currentJackpotId;
			sendRequest(request, receiveGetJackpotTimeLeftInSecondsResponse, (new GetJackpotTimeLeftInSeconds()).endpoint, false);
		}

		public function requestFetchCurrentJackPotGame(event:Event = null):void {
			var request:FetchJackPotRequest = new FetchJackPotRequest();
			request.gameid = controller.applicationData.jackpot.currentJackpotId;
			sendRequest(request, receiveFetchJackPotResponse, (new FetchJackPot()).endpoint, false);
		}

		public function requestGetCurrentJackPotGame(event:Event = null):void {
			var request:GetCurrentJackPotRequest = new GetCurrentJackPotRequest();
			sendRequest(request, receiveGetCurrentJackPotResponse, (new GetCurrentJackPot()).endpoint, false);
		}

		public function requestDeleteGamestates(listOfKeys:Array):void {
			var request:DeleteGamestateRequest = new DeleteGamestateRequest();
			request.uid = facebookData.userId;
			request.key = listOfKeys;
			Debug.trace("requestDeleteGamestatesRequest:  list of keys -> " + listOfKeys.length);
			sendRequest(request, receiveDeleteGamestateResponse, (new DeleteGamestate()).endpoint, false);
		}

		public function requestGenerateDonationURL(aKey:String, aValue:String):void {
			var request:GenerateDonationURLRequest = new GenerateDonationURLRequest();
			request.uid = facebookData.userId;
			request.key = aKey;
			request.value = aValue;
			sendRequest(request, receiveGenerateDonationURLResponse, (new GenerateDonationURL()).endpoint, false);
		}

		public function requestInitializeClient():void {
			var request:InitializeClientRequest = new InitializeClientRequest();
			request.uid = facebookData.userId;
			sendRequest(request, receiveInitializeClientResponse, (new InitializeClient()).endpoint, false);
		}

		public function requestStoreGamestateByKey(storeKey:String, storeValue:String):void{
			var request:StoreGamestateRequest = new StoreGamestateRequest();
			request.uid = facebookData.userId;
			
			var myState:GameState = new GameState();
			myState.key = storeKey;
			myState.value = storeValue;
			
			request.state = myState;
			Debug.trace("requestStoreGamestateByKey: "  + storeKey  + ":" +storeValue + " userId: " + facebookData.userId);
			sendRequest(request, receiveStoreGamestateResponse, (new StoreGamestate()).endpoint, true);
		}

		public function requestFetchGamestateByKey(requestedKey:String, uid:String = ""):void{
			Debug.trace("ServiceLayerCommunication::requestFetchGamestateByKey: " + requestedKey + ":" + uid);
			var request:FetchGamestateRequest = new FetchGamestateRequest();
			request.key = requestedKey;
			if(uid == ""){
				request.uid = facebookData.userId;
				sendRequest(request, receiveFetchGamestateResponse, (new FetchGamestate()).endpoint);
			}else{
				request.uid = uid;
				sendRequest(request, receiveFetchForeignGamestateResponse, (new FetchGamestate()).endpoint);
			}
		}

		public function requestFetchGamestates():void{
			var request:FetchGamestatesRequest = new FetchGamestatesRequest();
			request.uid = facebookData.userId;
			sendRequest(request, receiveFetchGamestatesResponse, (new FetchGamestates()).endpoint);
		}

		public function requestCatalog():void{
			var request:GetCatalogItemsRequest = new GetCatalogItemsRequest();
			request.uid = facebookData.userId;
			sendRequest(request, receiveGetCatalogItemsResponse, (new GetCatalogItems()).endpoint);
		}

		public function buyItem(aItem:CatalogItem):void{
			Debug.trace("ServiceLayerCommunication::buyItem: " + aItem.catalogId, Debug.SEND);
			var request:PurchaseRequest = new PurchaseRequest();
			request.itemId = aItem.catalogId;
			request.uid = facebookData.userId;
			sendRequest(request, receivePurchaseResponse, (new Purchase()).endpoint);
		}

		public function requestUserBalance(event:Event = null):void {
			var request:GetUserBalanceRequest = new GetUserBalanceRequest();
			request.uid = facebookData.userId;
			sendRequest(request, receiveUserBalanceResponse, (new GetUserBalance()).endpoint);
		}
		
		public function requestStartJackpotGame(event:Event = null):void {
			var request:StartJackPotGameRequest = new StartJackPotGameRequest();
			request.uid = facebookData.userId;
			
			sendRequest(request, receiveStartJackPotGameResponse, (new StartJackPotGame()).endpoint);
		}

		public function requestStartGame(event:Event = null):void {
			var request:StartGameRequest = new StartGameRequest();
			request.uid = facebookData.userId;
			sendRequest(request, receiveStartGameResponse, (new StartGame()).endpoint);
		}

		public function requestUpdateJackPotScore(aScore:int = 0):void {
			Debug.trace("ServiceLayerCommunication::requestUpdateJackPotScore: score -> " + aScore + ":" + controller.applicationData.gameId, Debug.SEND);
			var request:UpdateJackPotScoreRequest = new UpdateJackPotScoreRequest();
			request.uid = facebookData.userId;
			request.score = aScore;
			request.gameid = controller.applicationData.gameId;
			if(controller.applicationData.gameId == controller.applicationData.jackpot.currentJackpotId){
				sendRequest(request, receiveUpdateJackPotScoreResponse, (new UpdateJackPotScore()).endpoint);
			}
			else{
				controller.applicationData.jackpot.handleResultForClosedJackpot();
			}
		}
		
		public function requestUpdateScore(aScore:int = 0):void {
			Debug.trace("ServiceLayerCommunication::requestUpdateScore: score -> " + aScore + ":" + controller.applicationData.gameId, Debug.SEND);
			var request:UpdateScoreRequest = new UpdateScoreRequest();
			request.uid = facebookData.userId;
			request.score = aScore;
			request.gameid = controller.applicationData.gameId;
			sendRequest(request, receiveUpdateScoreResponse, (new UpdateScore()).endpoint);
		}

		public function requestGetJackpotLeaderProfile(aUserId:String):void {
			var request:GetUserProfileRequest = new GetUserProfileRequest();
			request.uid = aUserId;
			sendRequest(request, receiveGetJackpotLeaderProfileResponse, (new GetUserProfile()).endpoint);
		}

		public function requestGetUserProfile(event:Event = null):void {
			var request:GetUserProfileRequest = new GetUserProfileRequest();
			request.uid = facebookData.userId;
			sendRequest(request, receiveGetUserProfileResponse, (new GetUserProfile()).endpoint);
		}

		public function requestFriendsWithGameInstalled(event:Event = null):void {
			var request:GetFriendsWithGameInstalledRequest = new GetFriendsWithGameInstalledRequest();
			request.uid = facebookData.userId;
			sendRequest(request, receiveFriendsWithGameInstalled, (new GetFriendsWithGameInstalled().endpoint));
		}

		public function requestGetUsersProfiles(event:Event = null):void {
			var request:GetUsersProfilesRequest = new GetUsersProfilesRequest();
			Debug.trace("SLC::requestGetUsersProfiles: " + facebookData.friendIDs.length +":" + facebookData.friendIDs);
			request.uids = facebookData.friendIDs;
			sendRequest(request, receiveUsersProfilesResponse, (new GetUsersProfiles()).endpoint);
		}
		
		public function requestPurchase(aCatalogItem:CatalogItem):void {
			var request:PurchaseRequest = new PurchaseRequest();
			request.uid  = facebookData.userId;
			request.itemId = aCatalogItem.catalogId;
			sendRequest(request, receivePurchaseResponse, (new Purchase()).endpoint);
		}
		
		public function requestServerTimestamp():void {
			var request:GetCurrentTimestampRequest = new GetCurrentTimestampRequest();
			sendRequest(request, receiveServerTimestamp, (new GetCurrentTimestamp()).endpoint);
		}
	
		// ################################## response methods ##########################################

		public function receiveGetJackpotTimeLeftInSecondsResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveGetJackpotTimeLeftInSecondsResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetJackpotTimeLeftInSecondsResponse = new GetJackpotTimeLeftInSecondsResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("Communication:receiveGetJackpotTimeLeftInSecondsResponse: time left: " + response.jackpot + "  currentJackpotId: " + controller.applicationData.jackpot.currentJackpotId, Debug.DEBUG);
					controller.applicationData.jackpot.remainingTime = response.jackpot;
				}
			}catch(e:Error){
				Debug.trace("Communication:receiveGetJackpotTimeLeftInSecondsResponse: " + e.getStackTrace(), Debug.ERROR);
//				errorHandler(INVALID_RESPONSE_ERROR, "receiveFetchJackPotResponse");
			}
		}

		public function receiveFetchJackPotResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveFetchJackPotResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				Debug.trace("ServiceLayerCommunication::receiveFetchJackPotResponse: incomming data = " + data, Debug.DEFAULT);
				var response:FetchJackPotResponse = new FetchJackPotResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receiveFetchJackPotResponse: endTime=" + response.jackpot.endTime + " potsize=" + response.jackpot.potsize + " leaderId = " + response.jackpot.leaderId + " highscore = " + response.jackpot.highscore, Debug.FACEBOOK);	
					if(response.jackpot.leaderId != controller.applicationData.jackpot.jackpot.leaderId){
						if(response.jackpot.endTime == "0"){
							Debug.trace("ServiceLayerCommunication::receiveFetchJackPotResponse: NEW JACKPOT LEADER -> ID = " + response.jackpot.leaderId);
							requestGetJackpotLeaderProfile(response.jackpot.leaderId);
						}
					}
					controller.applicationData.jackpot.jackpot = response.jackpot;
				}
			}catch(e:Error){
				Debug.trace("Communication:receiveFetchJackPotResponse: " + e.getStackTrace(), Debug.ERROR);
//				errorHandler(INVALID_RESPONSE_ERROR, "receiveFetchJackPotResponse");
			}
		}
		
		public function receiveGetCurrentJackPotResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveGetCurrentJackPotResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetCurrentJackPotResponse = new GetCurrentJackPotResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)){
					Debug.trace("ServiceLayerCommunication::receiveGetCurrentJackPotResponse: OLD JACKPOTGAME-ID: " + controller.applicationData.jackpot.currentJackpotId, Debug.FACEBOOK);
					Debug.trace("ServiceLayerCommunication::receiveGetCurrentJackPotResponse: endTime=" + response.jackpot.endTime + " potsize=" + response.jackpot.potsize + " leaderId = " + response.jackpot.leaderId + " highscore = " + response.jackpot.highscore, Debug.FACEBOOK);	
					controller.applicationData.jackpot.jackpot = response.jackpot;
					controller.applicationData.jackpot.currentJackpotId = response.jackpot.gameid;
					requestGetJackpotLeaderProfile(response.jackpot.leaderId);
					
					Debug.trace("ServiceLayerCommunication::receiveGetCurrentJackPotResponse: NEW JACKPOTGAME-ID: " + controller.applicationData.jackpot.currentJackpotId, Debug.FACEBOOK);
					requestGetJackpotTimeLeftInSeconds();
				}
			}catch(e:Error){
				Debug.trace("Communication:receiveGetCurrentJackPotResponse: " + e.getStackTrace(), Debug.ERROR);
//				errorHandler(INVALID_RESPONSE_ERROR, "receiveGetCurrentJackPotResponse");
			}
		}


		public function receiveFireEventResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveFireEventResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:FireEventResponse = new FireEventResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					// nothing to do ...
				}
			}catch(e:Error){
				Debug.trace("Communication:receiveFireEventResponse: " + e.getStackTrace(), Debug.ERROR);
			}
		}

		public function receiveDeleteGamestateResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveDeleteGamestateResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:DeleteGamestateResponse = new DeleteGamestateResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receiveDeleteGamestateResponse: deleted keys: " + response.key, Debug.FACEBOOK);
				}
			}catch(e:Error){
				Debug.trace("Communication:receiveDeleteGamestateResponse: " + e.getStackTrace(), Debug.ERROR);
				errorHandler(INVALID_RESPONSE_ERROR, "receiveDeleteGamestateResponse");
			}
		}

		public function receiveGenerateDonationURLResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveGenerateDonationURLResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GenerateDonationURLResponse = new GenerateDonationURLResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receiveGenerateDonationURLResponse: " + response.url, Debug.FACEBOOK);
					dispatchEvent(new DonationURLEvent(DonationURLEvent.DONATION_URL_RECEIVED, response.url)); // TODO - donation key needed !
				}
			}catch(e:Error){
				Debug.trace("Communication:receiveGenerateDonationURLResponse: " + e.getStackTrace(), Debug.ERROR);
				errorHandler(INVALID_RESPONSE_ERROR, "receiveGenerateDonationURLResponse");
			}
		}

		public function receiveServerTimestamp(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveServerTimestamp", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetCurrentTimestampResponse = new GetCurrentTimestampResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					var livesTimestamp:int = (new Date()).getTime();
					Debug.trace("ServiceLayerCommunication::receiveServerTimestamp: server: " + response.timestamp + " client: " + livesTimestamp, Debug.FACEBOOK);
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveServerTimestamp");
			}
		}

		public function receiveStoreGamestateResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveStoreGamestateResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:StoreGamestateResponse = new StoreGamestateResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receiveStoreGamestateResponse: " + response.status.code, Debug.FACEBOOK);
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveStoreGamestateResponse");
			}
		}
		
		public function receiveFetchForeignGamestateResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveFetchForeignGamestateResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:FetchGamestateResponse = new FetchGamestateResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receiveFetchForeignGamestateResponse: " + response.state.key + " : " + response.state.value, Debug.DEBUG);
					dispatchEvent(new GameStateEvent(GameStateEvent.FOREIGN_GAMESTATE_RECEIVED, response.state));
				}
			}catch(e:Error){
				Debug.trace("ServiceLayerCommunication::receiveFetchForeignGamestateResponse:", Debug.WARNING);
				errorHandler(INVALID_RESPONSE_ERROR, "receiveFetchForeignGamestateResponse");
			}
		}

		public function receiveFetchGamestateResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveFetchGamestateResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:FetchGamestateResponse = new FetchGamestateResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					gameState.storeState(response.state);
				}
			}catch(e:Error){
				Debug.trace("ServiceLayerCommunication::receiveFetchGamestateResponse:", Debug.WARNING);
				errorHandler(INVALID_RESPONSE_ERROR, "receiveFetchGamestateResponse");
			}
		}

		public function receiveFetchGamestatesResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveFetchGamestatesResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:FetchGamestatesResponse = new FetchGamestatesResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					gameState.storeStates(response.state);
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveFetchGamestatesResponse");
			}
		}

		public function receivePurchaseResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receivePurchaseResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:PurchaseResponse = new PurchaseResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receivePurchaseResponse: bought: " + response.result.itemId, Debug.FACEBOOK);
					controller.inventory.addToIventory(controller.catalog.getItemById(String(response.result.itemId)),response.result.numItemsBought);
					facebookData.balance = response.result.balance;
				}else{
					// TODO - wann soll das geworfen werden????
					dispatchEvent(new Event(PURCHASE_ITEM_FAILED));
				}
			}catch(e:Error){
				Debug.trace("Communication:receivePurchaseResponse: " + e.getStackTrace(), Debug.ERROR);
				errorHandler(INVALID_RESPONSE_ERROR, "receivePurchaseResponse");
			}
		}

		public function receiveGetCatalogItemsResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveGetCatalogItemsResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetCatalogItemsResponse = new GetCatalogItemsResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receiveGetCatalogItemsResponse" + response.items, Debug.FACEBOOK);
					controller.catalog.items = response.items;
					
					for each(var item:CatalogItem in response.items){
						Debug.trace("item found: " + item.catalogId + ":" + item.title + ":" + item.price);
					}
				}else{
					Debug.trace("ServiceLayerCommunication::receiveGetCatalogItemsResponse" + response.items, Debug.WARNING);
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveGetCatalogItemsResponse");
			}
		}

		public function receiveUserBalanceResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveUserBalanceResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetUserBalanceResponse = new GetUserBalanceResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					Debug.trace("ServiceLayerCommunication::receiveUserBalanceResponse: " + response.balance.balance, Debug.FACEBOOK);
					facebookData.balance = response.balance;
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveUserBalanceResponse");
			}
		}
		
		public function receiveStartJackPotGameResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveStartJackPotGameResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:StartJackPotGameResponse = new StartJackPotGameResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)){
					controller.applicationData.gameId = response.gameId;
					Debug.trace("ServiceLayerCommunication::receiveStartJackPotGameResponse: " + response.gameId, Debug.FACEBOOK);
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveStartJackPotGameResponse");
			}
		}
		
		public function receiveUpdateJackPotScoreResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveUpdateJackPotScoreResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:UpdateJackPotScoreResponse = new UpdateJackPotScoreResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)){
					Debug.trace("ServiceLayerCommunication::receiveUpdateJackPotScoreResponse: " + response.gameResult, Debug.DEBUG);
					requestFetchCurrentJackPotGame();
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveUpdateJackPotScoreResponse");
			}
		}

		public function receiveStartGameResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveStartGameResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:StartGameResponse = new StartGameResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)){
					controller.applicationData.gameId = response.gameId;
					Debug.trace("ServiceLayerCommunication::receiveStartGameResponse: " + response.gameId, Debug.FACEBOOK);
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveStartGameResponse");
			}
		}

		public function receiveUpdateScoreResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveUpdateScoreResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:UpdateScoreResponse = new UpdateScoreResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)){
					// TODO - handle valid result
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR);
			}
		}

		public function receiveFriendsWithGameInstalled(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveFriendsWithGameInstalled", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetFriendsResponse = new GetFriendsResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)) {
					facebookData.friendIDs = response.friends;
					Debug.trace("response.friends: length=" + response.friends.length + " content:" + response.friends.toString() + "END");
					if(response.friends.length > 0){
						requestGetUsersProfiles();
					}
				}
			}catch(e:Error){
				Debug.trace("ServiceLayerCommunication::receiveFriendsWithGameInstalled: " + e.message + ":" + e.getStackTrace(), Debug.ERROR);
				errorHandler(INVALID_RESPONSE_ERROR, "receiveFriendsWithGameInstalled");
			}
		}

		public function receiveUsersProfilesResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveUsersProfilesResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetUsersProfilesResponse = new GetUsersProfilesResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)){
					Debug.trace("ServiceLayerCommunication::GetUsersProfilesResponse: buddy-count: " + response.profiles.length);
					facebookData.friendProfiles = response.profiles;
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveUsersProfilesResponse");
			}
		}

		public function receiveGetJackpotLeaderProfileResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveGetJackpotLeaderProfileResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetUserProfileResponse = new GetUserProfileResponse();
				response.readFromDataOutput(data);
				Debug.trace("ServiceLayerCommunication::receiveGetJackpotLeaderProfileResponse: return code: " + response.status.code);
				if(handleReturnCode(response.status.code)){
					controller.applicationData.jackpot.jackpotLeader = response.profile;
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveGetJackpotLeaderProfileResponse");
			}
		}



		public function receiveGetUserProfileResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveGetUserProfileResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:GetUserProfileResponse = new GetUserProfileResponse();
				response.readFromDataOutput(data);
				Debug.trace("ServiceLayerCommunication::receiveGetUserProfileResponse: return code: " + response.status.code);
				if(handleReturnCode(response.status.code)){
					facebookData.user = response.profile;
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveGetUserProfileResponse");
			}
		}
		
		public function receiveInitializeClientResponse(event:Event):void {
			Debug.trace("ServiceLayerCommunication::receiveInitializeClientResponse", Debug.RECEIVE);
			try{
				var data:ByteArray = ByteArray(event.target.data);
				var response:InitializeClientResponse = new InitializeClientResponse();
				response.readFromDataOutput(data);
				if(handleReturnCode(response.status.code)){
					facebookData.user = response.data.profile;
					controller.catalog.items = response.data.catalog;
					facebookData.friendIDs = response.data.friends;
					facebookData.balance = response.data.balance;
					gameState.storeStates(response.data.state);
					controller.featureList.setFeatures(response.data.features);
					if(facebookData.friendIDs.length > 0){
						requestGetUsersProfiles();
					}else{
						facebookData.friendProfiles = new Array();
					}
				}
			}catch(e:Error){
				errorHandler(INVALID_RESPONSE_ERROR, "receiveInitializeClientResponse");
			}
		}

		// ################################## generic stuff ##########################################

		public function sendRequest(message:Message, responseHandler:Function, slEndPoint:String, isWriteRequest:Boolean = false):void {
			Debug.trace("ServiceLayerCommunication::sendRequest: endpoint = " + slEndPoint + " isWriteRequest=" + isWriteRequest, Debug.SEND);
			
			isWriteRequest = true; // TODO - ActionQueue disabled - fixed in service layer ...
			
			var bytes:ByteArray = new ByteArray();
			message.writeToDataOutput(bytes);
			bytes.position = 0;
			Debug.trace("ServiceLayerCommunication::sendRequest: URL = " + (serviceURL + slEndPoint + ";gdfb=" + sessionId), Debug.DEBUG);				
			var request:URLRequest = new URLRequest(serviceURL + slEndPoint + ";gdfb=" + sessionId);
			request.method = "POST";
			request.contentType = "text/plain";
			request.data = bytes;
							
			try {
				var loader:ServiceLayerURLLoader = new ServiceLayerURLLoader();
				loader.addEventListener(Event.COMPLETE, responseHandler);
				loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
				loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
				loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, onHTTPStatus);
				loader.dataFormat = URLLoaderDataFormat.BINARY;
				loader.rpcTarget = serviceURL + slEndPoint;
				
				if(isWriteRequest){
					new ServiceLayerRequestAction(loader, request, true, slEndPoint);
				}else{
					loader.load(request);
				}
			} catch (error:Error) {
				Debug.trace("ServiceLayerCommunication::sendRequest: Unable to load requested document.", Debug.ERROR);
				errorHandler(SERVER_NOT_AVAILABLE_ERROR);
			}
		}

		/**
		 * check if a incomming message is marked as OK
		 */
		private function handleReturnCode(aReturnCode:int):Boolean {
			switch(aReturnCode){
				case MESSAGE_OK:
					return true;
					
				case MESSAGE_ERROR_1:
					errorHandler("error message 1");
					return false;
				
				case SESSION_EXPIRED:
					sessionExpiredHandler();
					return false;
					
				default:
					errorHandler(UNKNOWN_RETURN_CODE_ERROR);
					return false;
			}
		}

		private function errorHandler(errorType:String = "unknown", errorFunction:String = "not set"):void {
			Debug.trace("ServiceLayerCommunication::ErrorHandler: errorType: " + errorType + " call: " + errorFunction, Debug.ERROR);
			dispatchEvent(new CommunicationErrorEvent(errorType));
		}

		private function sessionExpiredHandler(event:Event = null):void {
			Debug.trace("ServiceLayerCommunication::sessionExpiredHandler: ", Debug.WARNING);
			tracker.track("connection.session_expired");
			dispatchEvent(new Event(SESSION_EXPIRED_ERROR));
		}
		
		private function onHTTPStatus(event:HTTPStatusEvent):void {
			if(event.status >= 400){
				Debug.trace("ServiceLayerCommunication::onHTTPStatus: " + event.status, Debug.WARNING);
				try{
					tracker.track("connection.http_status." + event.status + "." + ServiceLayerURLLoader(event.target).rpcTarget);
				}catch(e:Error){
					tracker.track("connection.http_status." + event.status);
				}
			}
		}

		private function onIOError(event:IOErrorEvent):void {
			var rpcTarget:String = ServiceLayerURLLoader(event.target).rpcTarget;
			var splitter:Array   = rpcTarget.split("/");
			var endPoint:String  = splitter[splitter.length - 1];
			Debug.trace("ServiceLayerCommunication::onIOError" + event + " endPoint -> " + endPoint, Debug.ERROR);
			// filter events for users ... - // FIXME - workaround for 403 errors ...
			switch(endPoint){
				case "jackPotCurrentGame":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for jackPotCurrentGame", Debug.WARNING);
					break;
					
				case "jackpotTimeLeftInSeconds":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for jackpotTimeLeftInSeconds", Debug.WARNING);
					break;
					
				case "jackPotFetchGame":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for jackPotFetchGame", Debug.WARNING);
					break;

				case "fireEvent":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for fireEvent", Debug.WARNING);
					break;
					
				case "getUserProfile":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for getUserProfile", Debug.WARNING);
					break;
					
				case "getUsersProfiles":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for getUsersProfiles", Debug.WARNING);
					break;
					
				case "storeGameState":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for storeGameState", Debug.WARNING);
					break;
					
				case "startGame":
					Debug.trace("ServiceLayerCommunication::onIOError: ERROR MESSAGE SKIPPED for startGame", Debug.WARNING);
					break;
					
				default:
					errorHandler(GENERAL_NETWORK_ERROR);
			}
			try{
				tracker.track("connection.ioerror." + rpcTarget);
			}catch(e:Error){
				tracker.track("connection.ioerror.unknown");
			}
		}

		private function onSecurityError(event:SecurityErrorEvent):void {
			Debug.trace("ServiceLayerCommunication::onSecurityError: " + event, Debug.ERROR);
//			var rpcTarget:String = ServiceLayerURLLoader(event.target).rpcTarget;
//			var splitter:Array   = rpcTarget.split("/");
//			var endPoint:String  = splitter[splitter.length - 1];
//			Debug.trace("ServiceLayerCommunication::onIOError" + event + " endPoint -> " + endPoint, Debug.ERROR);
//			// filter events for users ...
//			switch(endPoint){
//				case "jackPotCurrentGame":
//					Debug.trace("ServiceLayerCommunication::onSecurityError: ERROR MESSAGE SKIPPED for jackPotCurrentGame", Debug.WARNING);
//					break;
//					
//				case "jackpotTimeLeftInSeconds":
//					Debug.trace("ServiceLayerCommunication::onSecurityError: ERROR MESSAGE SKIPPED for jackpotTimeLeftInSeconds", Debug.WARNING);
//					break;
//					
//				case "jackPotFetchGame":
//					Debug.trace("ServiceLayerCommunication::onSecurityError: ERROR MESSAGE SKIPPED for jackPotFetchGame", Debug.WARNING);
//					break;
//					
//				case "initializeClient":
//					Debug.trace("ServiceLayerCommunication::onSecurityError: ERROR MESSAGE SKIPPED for initializeClient", Debug.WARNING);
//					break;
//					
//				default:
//					errorHandler(GENERAL_NETWORK_ERROR);
//			}
			try{
				tracker.track("connection.security_error." + ServiceLayerURLLoader(event.target).rpcTarget);
			}catch(e:Error){
				tracker.track("connection.security_error.unknown");
			}
		}
	}
}

